﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace Jaiden.Runtime.InteropServices
{
    public class UTF8Marshaler : ICustomMarshaler
    {
        private static readonly UTF8Marshaler Instance = new UTF8Marshaler();

        public void CleanUpManagedData(object managedObj)
        {
        }

        public void CleanUpNativeData(IntPtr pNativeData)
        {
            Marshal.FreeHGlobal(pNativeData);
        }

        public int GetNativeDataSize()
        {
            return -1;
        }

        public IntPtr MarshalManagedToNative(object managedObj)
        {
            if (ReferenceEquals(managedObj, null))
            {
                return IntPtr.Zero;
            }

            if (!(managedObj is string))
            {
                throw new InvalidOperationException();
            }

            var utf8Bytes = Encoding.UTF8.GetBytes(managedObj as string);
            var ptr = Marshal.AllocHGlobal(utf8Bytes.Length + 1);
            Marshal.Copy(utf8Bytes, 0, ptr, utf8Bytes.Length);
            Marshal.WriteByte(ptr, utf8Bytes.Length, 0);
            return ptr;
        }

        public object MarshalNativeToManaged(IntPtr pNativeData)
        {
            return PtrToStringUTF8(pNativeData);
        }

        public static ICustomMarshaler GetInstance(string cookie)
        {
            return Instance;
        }

        public static string PtrToStringUTF8(IntPtr ptr)
        {
            if (ptr == IntPtr.Zero)
            {
                return null;
            }

            var bytes = new List<byte>();
            for (var offset = 0;; offset++)
            {
                var b = Marshal.ReadByte(ptr, offset);
                if (b == 0)
                {
                    break;
                }

                bytes.Add(b);
            }

            return Encoding.UTF8.GetString(bytes.ToArray(), 0, bytes.Count);
        }
    }
}